package com.simple.crawler.core.listener;

import com.simple.crawler.annotation.Getter;
import com.simple.crawler.annotation.Setter;
import com.simple.crawler.aop.AopHelper;
import com.simple.crawler.aop.Listener;
import com.simple.crawler.connect.Response;
import com.simple.crawler.constant.Const;
import com.simple.crawler.core.Crawler;
import com.simple.crawler.core.CrawlerContext;
import com.simple.crawler.core.Task;
import com.simple.crawler.core.TaskExecutor;
import com.simple.crawler.core.task.SingleTask;
import com.simple.crawler.utils.IOUtils;
import com.simple.crawler.utils.ReflectUtils;
import com.simple.crawler.utils.StringUtils;
import net.sf.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;

@Component
public interface TaskListener extends Listener {

    @Override
    default boolean filter(String method) {
        return StringUtils.isContains("run", method);
    }

    default void doGetter(Task task, Method method, Object[] objects, MethodProxy methodProxy) throws Exception {
        Crawler crawler = CrawlerContext.getCrawler(task.getCrawlerId());
        if (crawler == null) {
            return;
        }
        ReflectUtils.getFields(task.getClass(), Getter.class, new ArrayList<>()).forEach(field -> ReflectUtils.setFieldValue(task, field.getName(), crawler.getCache().get(field.getAnnotation(Getter.class).name())) );
    }

    default void doSetter(Task task, Method method, Object[] objects, MethodProxy methodProxy) throws Exception {
        Crawler crawler = CrawlerContext.getCrawler(task.getCrawlerId());
        if (crawler == null) {
            return;
        }
        Response response = crawler.getCache().get(task.getId(), Const.TASK_RESULT, Response.class);
        if (response == null || !response.isSuccess()) {
            return;
        }
        ReflectUtils.getFields(task.getClass(), Setter.class, new HashMap<>()).forEach((field, setter) -> CrawlerContext.getObj(setter.resolver()).doSetter(task, field, (String) response.getContent()));
        ReflectUtils.invoke(task, "recovery", new Object[]{}, Void.class);
    }

    default void dispatchTask(Task task, Method method, Object[] objects, MethodProxy methodProxy) throws Exception {
        Crawler crawler = CrawlerContext.getCrawler(task.getCrawlerId());
        if (crawler == null) {
            return;
        }
        if (task.getDispatchUrl() == null || task.getDispatchUrl().isEmpty()) {
            logger.debug("无可处理链接");
            return;
        }
        crawler.getCache().get(task.getId()).clear();
        int taskIndex = task.getIndex() + 1;
        if (taskIndex >= crawler.getTaskList().length) {
            return;
        }
        task.getDispatchUrl().forEach(url -> TaskExecutor.addTask(AopHelper.getAopHelper().initObj(crawler.getTaskList()[taskIndex], new Object[]{crawler.getId(), taskIndex, url})));
    }

    @Override
    default Object invoke(Object o, Method method, Object[] objects, MethodProxy proxy) throws Throwable {
        long start = System.currentTimeMillis();
        logger.info("爬虫ID【{}】,任务处理类【{}】,任务ID【{}】,任务类型【{}】,处理url【{}】",((Task) o).getCrawlerId(), o.getClass().getTypeName(), ((Task) o).getId(), o instanceof SingleTask ? "单页任务" : "多页任务", ((Task) o).getUrl());
        before(o, method, objects, proxy);
        doGetter((Task) o, method, objects, proxy);
        Object result = proxy.invokeSuper(o, objects);
        doSetter((Task) o, method, objects, proxy);
        //分发任务
        dispatchTask((Task) o, method, objects, proxy);
        after(o, method, objects, proxy);
        long end = System.currentTimeMillis();
        logger.info("本次共耗时:{}ms,响应值:{}", end - start, result);
        return result;
    }

}
